第 1 章 Verilog 的基本知识第 2 章 Verilog 语法的基本概念2.1 Verilog 模块的基本概念2.2 Verilog 用于模块的测试第 3 章 模块与数据类型及其运算符3.1 模块结构3.2 数据类型3.2.1 常量3.2.2 变量第 4 章 运算符、赋值语句和结构说明语句第 5 章 流程控制语句第 6 章 结构语句、系统任务、函数语句和显示系统任务6.1 系统说明语句6.1.1 initial6.1.2 always6.2 task 和 function6.2.1 说明语句介绍6.2.2 task 说明语句6.2.3 function 说明语句6.2.4 函数的使用举例1 奇偶校验位2 左右移位寄存器6.2.5 自动递归函数6.2.6 常量函数6.2.7 带符号函数6.4 常用的系统任务6.4.1 $display 和 $write6.4.2 文件输出6.4.3 显式层次6.4.4 选通显示6.4.5 值变转储文件第 7 章 调试用系统任务和编译预处理语句7.1 $monitor7.2 $time 与 $realtime7.3 $finish 与 $stop7.4 $readmemb 与 $readmemh7.6 $random7.7 编译预处理第 12 章 状态机第 13 章 编写可综合的代码
电路结构在 5000 门以上:
软核:Verilog HDL 模型
固核:电路结构编码文件
硬核:电路结构版图掩膜
设计过程
编写 Verilog 模块
综合(synthesis)
1// 例 2.1:二选一(由 always 语句实现)2module mux2(out, a, b, sl);3 input a, b, sl;4 output out;5 6 reg out; // 用于 always 语句7 always @(sl or a or b)8 if (sl) out a;9 else out b;10endmodule
xxxxxxxxxx111// 例 2.2:二选一(由逻辑表达式实现)2module mux2(out, a, b, sl);3 input a, b, sl;4 output out;5 6 wire nsl, sela, selb; // 内部连接线7 assign nsl sl; // 求反8 assign sela a nsl;9 assign selb b sl;10 assign out sela selb;11endmodule
xxxxxxxxxx101// 例 2.3:二选一(由逻辑门实现)2module mux2(out, a, b, sl);3 input a, b, sl;4 output out;5 6 not u1(nsl, sl);7 and #1 u2(sela, a, nsl);8 and #1 u3(sleb, b, sl);9 or #1 u4(out, sela, selb);10endmodule
xxxxxxxxxx91// 例 2.4:三位加法器(由连续赋值语句)2module adder(cout, sum, a, b, cin);3 input[2:0] a, b; // 三比特输入4 input cin; // 输入进位5 output cout; // 输出进位6 output[2:0] sum; // 三比特输出7 8 assign {cout, sum} a b cin;9endmodule
xxxxxxxxxx71// 例 2.5;比较器(连续赋值语句)2module compare2(equal, a, b);3 output equal; // 是否相等4 input[1:0] a, b;5 6 assign equal (ab) 1 : 0;7endmodule
xxxxxxxxxx81// 例 2.6:三态门选择器2module trist2(out, in, enable);3 output out;4 input in, enable;5 6 bufif1 mybuf(out, in, enable);7 // 定义名为 mybuf 的三态门驱动器元件8endmodule
x1// 例 2.7:三态门选择器2
3// 子模块 mytri4module mytri(out, in, enable);5 output out;6 input in, enable;7 assign out enable in : 'bz; // 高阻态8endmodule9
10// 上层模块11module trist1(sout, sin, ena);12 output sout;13 input sin, ena;14 mytri tri_inst(15 .out(sout),16 .in(sin),17 .enable(ena)18 ); // 实例化部件19endmodule
xxxxxxxxxx261// 例 2.8:对例 2.1 - 2.3 的测试文件2`include "mux2.v"3module t;4 reg ain, bin, select;5 reg clock; // 时钟信号6 wire outw;7 8 // 只能在 testbench 中使用 initial,用于初始化参数9 initial begin10 ain 0; bin 0;11 select 0; clock 0;12 end13 14 always #50 clock clock; // 时钟信号周期为 10015 always #10000 select select; // 选通信号周期为 1000016 17 always @(posedge clock) begin18 #1 ain {} 2;19 #3 bin {} 2;20 end21 22 mux2 m(23 .a(ain), .b(bin),24 .out(outw), .sl(select)25 );26endmodule
模块的结构
模块的表示
程序模块
电路图符号
模块的组成
输入输出管脚分配
管脚间的逻辑关系
模块的端口
模块端口的定义
只标明端口:模块名(端口1, 端口2)
标明 I/O 口:模块名(input[n-1:0] 端口1, output 端口2)
模块端口的引用
按照顺序:模块名(信号1, 信号2)
表明端口:模块名(.端口1(信号1), .端口2(信号2))
模块内容
I/O 说明(也可以在定义端口时说明)
input[n-1:0] 端口1, 端口2;
output[n-1:0] 端口1, 端口2;
端口默认为 wire 型.
内部信号
reg[n-1:0] 变量1, 变量2;
wire[n-1:0] 变量1, 变量2;
功能定义
assign 语句:assign a = ~(b ^ c);
用实例元件:and #2 u1(q, a, b);
aways 语句:always @(posedge clk) begin ...; end
注意事项
连续赋值语句(即 assign)表示将变量用导线(与逻辑门)相连.
模块中所有过程块(如 initial 块、always 块)、连续赋值语句、实例引用语句,都是并行的.
只有连续赋值语句和实例引用语句,可以独立于过程块而存在于模块的功能定义部分.
数字
表示方法(前缀 0 可省略不写)
<位宽>'<进制><数字>,如 8'b10101100
'<进制><数字>,默认位宽一般为 32 位(与系统有关)
<数字>,默认位宽、默认为十进制
数据类型
整型常量:二进制 b/B、十进制 d/D、十六进制 h/H、八进制 o/O
不定值:x,如 4'b10x0
高阻值:z 或 ?,如 4'dz 或 8'h32?
负数:写在表达式前,如 -8'd5
下划线:用在数字间,无实意,仅用于提高易读性.
缺省位宽
整数:10 = 32'd10
负数:-1 = -32'd1 = 32'hFFFFFFFF
不定值:'BX = 32'BX = 32'BXXX...X
字符串:"AB" = 16'h4142
参数:parameter 参数1 = 表达式1, 参数2 = 表达式2;
xxxxxxxxxx271// 例 3.22// Test.v3`include "Top.v"4`include "Block.v"5`include "Annotate.v"6module Test;7 wire W;8 Top T();9endmodule10
11// Top.v12module Top;13 wire W;14 Block B1();15 Block B2();16endmodule17
18// Block.v19module Block;20 Parameter P 0;21endmodule22
23module Annotate;24 defparam25 Test.T.B1.P 2, // 注意这里是逗号26 Test.T.B2.P 3;27endmodule
在 Verilog 中,所有变量都是静态的.
网络数据类型:不能存储值,必须受到驱动器(如连续赋值语句)的驱动
wire 型
wire[n-1:0] a, b;
wire[n:1] a, b;
reg 型
reg[n-1:0] rega;
可赋正值,可赋负值
被定义的信号将用在 always
memory 型
reg[n-1:0] 存储器名[m-1:0];
reg[n-1:0] 存储器名[m:1];
表示存储器有 m 个 n 位存储器
读写操作:mema[3] = 0;
tri 型
case 等式运算符:=== 和 !== 对不定值 x 和高阻值 z 也进行比较,完全一致才为 1.
位拼接运算符
{a, b[1:0], w, 3'b101}
{a, b[1], b[0], w, 1'b1, 1'b0, 1b'1}
{b, {2{a, b}}}
{b, a, b, a, b}
缩进运算符(单目运算符)
xxxxxxxxxx51reg[2:0] A;2reg B;3B A;4// 相当于5B A[0] A[1] A[2];赋值语句
非阻塞赋值方式
b <= a;
所赋的变量值不能立即后续语句使用.
块结束后才能完成这次赋值操作.
不要滥用,避免生成不必要的触发器.
阻塞赋值方式
b = a;
赋值语句执行完成之后,b 的值立即改变.
时序逻辑电路中建议不要这样写.
if 语句
条件语句必须在过程块语句中使用,即 initial 和 always 中
建议用 begin end 标明逻辑
xxxxxxxxxx61if (test1) statement1;2else if (test2) begin3 if (test3) statement2;4 else statement3;5end6else statement4;case 语句
所有表达式值的位宽必须相等.
不能用 'bx 代替 n'bz.
如果 if 或 case 没有为变量的所有可能都赋值,则会生成锁存器.
建议用 else 或 default 赋值,以避免自动生成锁存器.
xxxxxxxxxx111// 例 5.12case (select[1:2])3 2'b00: result 0;4 2'b01: result flaga;5 2'b0x,6 2'b0z: result flaga 'bx : 0;7 2'b10: result flagb;8 2'bx0,9 2'bz0: result flagb 'bx : 0;10 default: result 'bx;11endcaseforever 语句
常用于产生周期的波形,用于仿真测试信号.
必须写在 initial 块中.
xxxxxxxxxx31forever begin2 statements;3endrepeat 语句
xxxxxxxxxx171// 乘法器2paramter size 8, longsize 16;3reg[size:1] opa, opb;4reg[longsize:1] result;5
6begin: mult // 块语句名7 reg[longsize:1] shift_opa, shift_opb;8 shift_opa opa;9 shift_opb opb;10 result 0;11 repeat(size) begin12 if (shift_opb[1])13 result result shift_opa;14 shift_opa shift_opa << 1;15 shift_opb shift_opb >> 1;16 end17end
while 语句
xxxxxxxxxx151// 对八位二进制数华中值为 1 的位进行计数2reg[7:0] rega;3
4begin: count1s5 rega 2'b1011_0110;6 7 reg[7:0] tempreg;8 count 0;9 tempreg rega;10 while (tempreg) begin11 if (tempreg[0])12 count count 1;13 tempreg tempreg >> 1;14 end15end
for 语句
xxxxxxxxxx61// 例 5.7:用 for 语句初始化2begin: init_mem3 reg[7:0] i;4 for (i 0; i < memsize; i i 1)5 memory[i] 0;6endxxxxxxxxxx121// 例 5.8:用 for 语句实现乘法器2paramter size 8, longsize 16;3reg[size:1] opa, opb;4reg[longsize:1] result;5
6begin: mult // 块语句名7 integer i;8 result 0;9 for (i 1; i < size; i i 1)10 if (opb[i])11 result result (opa << (i1));12endxxxxxxxxxx81// 用 for 语句对八位二进制数华中值为 1 的位进行计数2begin: count1s3 reg[7:0] tempreg;4 count 0;5 for (tempreg rega; tempreg; tempreg tempreg >> 1)6 if (tempreg[0])7 count count 1;8end
块语句
顺序块
xxxxxxxxxx91// 例 4.52parameter d 50; // 声明 d 是一个参数3reg[7:0] r; // 8 位寄存器变量4begin5 #d r 'h35;6 #d r 'hE2; // 过了 d 个单位时间后,再经过 d 个单位时间7 #d > end_wave;8 // 表示触发事件 end_wave 使其翻转9end并行块
xxxxxxxxxx61// 例 4.62fork3 #100 r 'hE2;4 #50 r 'h35; // 顺序是不重要的;5 #150 > end_wave;6join块语句可以嵌套
块语句的命名
命名块中可以声明局部变量
命名块中声明的变量可以通过层次引用进行访问
命名块可以被禁用
xxxxxxxxxx91// 例 5.12:命名块的层次引用2module top;3 initial begin: block14 integer i; // top.block1.i5 end6 initial fork: block27 reg i; // top.block2.i8 join9endmodulexxxxxxxxxx181// 例 5.13:命名块的禁用2// 在标志寄存器中查找第一个非零位3reg[15:0] flag;4integer i; // 用于计数5
6initial begin7 flag 16'b 0010_0000_0000_0000;8 i 0;9 begin: block110 while (i < 16) begin11 if (flag[i]) begin12 ("TRUE bit at %d", i);13 disable block1;14 end15 i i 1;16 end17 end18end
5.7 生成块
5.7.1 循环生成语句
xxxxxxxxxx141// 例 5.14:对两个 N 位总线变量进行按位异或2module bitwise_xor(out, i0, i1);3 paramter N 32;4 output[N1 : 0] out;5 input[N1 : 0] i0, i1;6 7 genvar j; // 仿真时该变量在设计中不存在8 generate9 for (j 0; j < N; j j 1)10 begin: xor_loop11 xor g1 (out[j], i0[j], i1[j]);12 end13 endgenerate14endmodulexxxxxxxxxx171// 例 5.14 的另一种编写形式2module bitwise_xor(out, i0, i1);3 paramter N 32;4 output[N1 : 0] out;5 input[N1 : 0] i0, i1;6 7 reg[N1 : 0] out;8 9 genvar j;10 generate11 for (j 0; j < N; j j 1)12 begin: bit13 always@(i0[j] or i1[j])14 out[j] i0[j] i1[j];15 end16 endgenerate17endmodulexxxxxxxxxx291// 例 5.15:用循环生成语句描述的脉动加法器2module ripple_adder(co, sum, a0, a1, ci);3 parameter N 4; // 默认总线位宽为 44 output[N1 : 0] sum;5 output co;6 input[N1 : 0] a0, a1;7 input ci;8 9 wire[N1 : 0] carry;10 assign carry[0] ci;11 12 genvar i;13 generate14 for (i 0; i < N; i i 1) begin: r_loop15 wire t1, t2, t3;16 xor g1(t1, a0[i], a1[i]);17 xor g2(sum[i], t1, carry[i]);18 and g3(t2, a0[i], a1[i]);19 and g4(t3, t1, carry[i]);20 or g5(carry[i1], t2, t3);21 end22 endgenerate23 24 // 以 or 为例,上述生成块会生成以下层次实例名25 // or: r_loop[0].g5, r_loop[1].g5, r_loop[2].g5, r_loop[3].g526 // 线网也会连接起来:r_loop[0].t1, r_loop[1].t2 等等;27 28 assign co carry[N];29endmodule
5.7.2 条件生成语句
xxxxxxxxxx251// 例 5.16:使用条件生成语句实现参数化乘法器2module multiplier(a0, a1, product);3 // 可重新定义 (defparam) 的参数4 parameter a0_width 8;5 parameter a1_width 8;6 7 // 本地参数8 // 1. 不能用参数重新定义9 // 2. 也不能在实例引用时通过传递参数语句,即 #(参数1, 参数2) 的方法修改10 localparam product_width a0_width a1_width;11 12 // 端口声明语句13 input[a0_width1:0] a0;14 input[a1_width1:0] a1;15 output[product_width1:0] product;16 17 // 根据位数选择不同类型的乘法器18 generate19 if (a0_width < 8 a1_width < 8)20 cal_multiplier #(a0_width, a1_width) m0(product, a0, a1);21 // # 用于给参数赋值22 else23 tree_multiplier #(a0_width, a1_width) m0(product, a0, a1);24 endgenerate25endmodule
5.7.3 case 生成语句
xxxxxxxxxx211// 例 5.17:case 生成语句生成 N 位加法器2module adder(co, sum, a0, a1, ci);3 // 声明的参数可以重新定义4 parameter N 4; // 默认的总线位宽为 45 6 // 端口声明7 output[N1:0] sum;8 output co;9 input[N1:0] a0, a1;10 input ci;11 12 // 根据总线位宽,调用相应的加法器(实例引用)13 // 参数 N 在调用(实例引用)时可重新定义14 generate15 case (N)16 1: adder_1bit adder1(co, sum, a0, a1, ci);17 2: adder_2bit adder2(co, sum, a0, a1, ci);18 default: adder_cla #(N) adder3(co, sum, a0, a1, ci);19 endcase20 endgenerate21endmodule
5.8 举例
5.8.1 四选一多路选择器
写法一:
xxxxxxxxxx161// 例 5.18:四选一多路选择器——写法一2module mux4_to_1(out, i0, i1, i2, i3, s1, s0);3 input i0, i1, i2, i3;4 input s1, s05 output reg out;6 7 always @() begin8 case ({s1, s0})9 2'b00: out i0;10 2'b01: out i1;11 2'b10: out i2;12 2'b11: out i3;13 default: out 1'bx;14 endcase15 end16endmodule
写法二:
xxxxxxxxxx101// 例 5.18:四选一多路选择器——写法一2module mux4_to_1(out, i, s);3 input[3:0] i;4 input[1:0] s;5 output reg out;6 7 // 试试能不能这样写,一是数组直接写 s,二是把 s 放在下标中8 // 哈哈,测试过了,都是可以的9 always @(s or i) out i[s];10endmodule
上述代码的 testbench:
xxxxxxxxxx161// testbench of mux4_to_12`timescale 1ns10ps3module mux4_to_1_tb;4 reg[3:0] i;5 reg[1:0] s;6 wire out;7 8 mux4_to_1 mux4_to_1(.i(i), .s(s), .out(out));9
10 always #10 i < i 1;11 always #160 s < s 1;12 initial begin13 i < 0; s < 0;14 #640 ;15 end16endmodule
5.8.2 四位计数器
xxxxxxxxxx281// 例 5.19:四位二进制计数器2module counter(Q, clock, clear);3 output reg[3:0] Q;4 input clock, clear;5 6 always @(posedge clear or negedge clock) begin7 if (clear) Q < 4'd0; // 为了生成包含触发器的时序逻辑,使用非阻塞赋值8 else Q < Q 1; // 四位寄存器,无需模 169 end10endmodule11
12// testbench of counter13`timescale 1ns10ps14module counter_tb;15 reg clock, clear;16 wire[3:0] Q;17
18 counter counter(.clock(clock), .clear(clear), .Q(Q));19
20 always #10 clock < clock;21 always #250 clear < clear;22 initial begin23 clock < 0;24 clear < 1;25 #1000 ;26 end27endmodule28
一个模块可以有多个 initial 块,并且都是并行运行的.
如果没有时序控制,则会产生仿真死锁,如 always A <= B;
敏感事件列表,既可以用 or 也可以用 ,,如 always @(A, B) ...
@* 或 @(*) 可以将所有输入变量都包括进敏感列表.
电平敏感时序控制,即等到条件为真时才运行,如
always wait(ena) #20 count <= count + 1;
函数与主模块共用一个仿真时间单位,而任务可自定义.
函数不能启动任务,而任务能启动其它任务和函数.
函数至少需要一个输入变量,而任务可以没有或有多个任何类型的变量.
函数返回一个值,而任务则不返回值.
xxxxxxxxxx21switch_bytes(old_word, new_word); // 任务2new_word switch_bytes(old_word); // 函数
xxxxxxxxxx81// 任务的定义2task<任务名>;3 <端口及数据类型声明语句>4 <语句>5endtask6
7// 任务的调用8<任务名>(端口1, 端口2, ...)
xxxxxxxxxx411// 例 6.9:描述交通信号灯行为的模块2// 该模块只是一个行为模块,不能综合成电路网表3`timescale 1ns10ps4module traffic_lights;5 reg clock, red, amber, green;6 parameter on 1, off 0;7 parameter red_tics 350, amber_tics 30, green_tics 200;8 9 // 提问:可不可以写成 red = amber = green = off;10 // 即赋值语句有没有返回值?那样连 begin end 都省了,直接一行代码.11 // 试过了,只有非阻塞赋值都可以这样写12 // 不!这样编译虽然能过,但是结果却有问题,都显示不定值了.13 // initial red <= amber <= green <= off;14 15 // 交通灯控制程序16 always begin17 red on; light(red, red_tics);18 green on; light(green, green_tics);19 amber on; light(amber, amber_tics);20 end21 22 // 定义交通灯开启时间的任务23 task light;24 output color;25 input[31:0] tics;26 begin27 repeat(tics)28 @(posedge clock); // 等待 tics 个时钟的上升沿29 color off; // 之后关灯30 end31 endtask32 33 // 产生时钟脉冲34 initial begin35 clock < 0;36 red < off; amber < off; green < off;37 #10000 ;38 end39 always #1 clock < clock;40endmodule41
xxxxxxxxxx81// 函数的定义2function <返回值的类型或范围> (函数名):3 <端口说明语句>4 <变量类型说明语句>5 begin6 <语句>7 end8endfunction
xxxxxxxxxx81// 例子2function [7:0] getbyte;3 input [15:0] address;4 begin5 <说明语句>6 getbyte result_expression7 end8endfunction
使用规则
函数的定义不能包含任何时间控制语句
函数不能启动任务
定义函数时至少要有一个输入参量
xxxxxxxxxx251// 例 6.10:阶乘函数的定义与调用2module tryfact;3 // 函数的定义4 function[31:0] factorial;5 input[3:0] operand;6 reg[3:0] index;7 begin8 factorial 1;9 for (index 2; index < operand; index index 1)10 factorial index factorial;11 end12 endfunction13 14 // 函数的测试15 reg[31:0] result;16 reg[3:0] n;17 initial begin18 result 1;19 for (n 2; n < 9; n n 1) begin20 ("%d: %d, ", n, result);21 result n factorial(n) (2n 1);22 end23 ("Final result = %d", result);24 end25endmodule
xxxxxxxxxx251// 例 6.11:奇偶校验位的计算2module parity;3 reg[31:0] addr;4 reg parity;5 6 initial begin7 addr < 32'h3456_789a;8 #10 addr < 32'hc4c6_78ff;9 #10 addr < 32'hff56_ff9a;10 #10 addr < 32'h3faa_aaaa;11 end12 13 always @(addr) begin14 parity calc_parity(addr); // 第一次启动,下一行是第二次15 ("Parity calculated = %b", calc_parity(addr));16 end17 18 // 定义奇偶校验计算函数19 function calc_parity;20 input[31:0] address;21 begin22 calc_parity address; // 返回所有地址位的异或值23 end24 endfunction25endmodule注意上述代码中的 ^addresss
xxxxxxxxxx61// 例 6.12:使用 C 风格进行变量声明的函数定义2function calc_parity(input[31:0] address);3 begin4 calc_parity address;5 end6endfunction
xxxxxxxxxx201// 例 6.13:定义一个包含移位函数的模块2module shifter;3 `define LEFT_SHIFT 1'b04 `define RIGHT_SHFIT 1'b15 reg[31:0] addr, left_addr, right_addr;6 reg control;7 8 always @(addr) begin9 left_addr shift(addr, `LEFT_SHIFT);10 right_addr shift(addr, `RIGHT_SHIFT);11 end12 13 function[31:0] shift;14 input[31:0] address;15 input control;16 begin17 shift (control `LEFT_SHIFT) (address << 1) : (address >> 1);18 end19 endfunction20endmodule
Verilog 中的函数默认不能递归调用,如果同时调用同一块地址空间,那么计算结果将不确定.
xxxxxxxxxx191// 例 6.14:自动递归函数2module top;3 function automatic integer factorial;4 input[31:0] oper;5 integer i;6 begin7 if (operand > 2)8 factorial factorial(oper 1) oper; // 递归9 else10 factorial 1;11 end12 endfunction13 14 integer result;15 intial begin16 result facotrial(4);17 ("Factorial of 4 is %0d", result);18 end19endmodule
xxxxxxxxxx121// 例 6.15:常量函数2module ram(...);3 parameter RAM_DEPTH 256;4 input[clogb2(RAM_DEPTH) 1 : 0] addr_bus;5 ...6 function integer clogb2(input integer depth);7 begin8 for (clogb2 0; depth > 0; clogb2 clogb2 1)9 depth depth >> 1;10 end11 endfunction12endmodule
xxxxxxxxxx81// 例 6.16:带符号函数2module top;3 ...4 function signed[63:0] compute_signed(input[63:0] vector);5 //6 endfunction7 ...8endmodule


xxxxxxxxxx91// 例 6.172module disp;3 initial begin4 ("\\\t%%\n\"\123");5 \ \\ 表示反斜杠,\t 表示制表符, 表示百分号6 \n 表示换行符 ,\" 表示双引号,\123 表示 S7 \8 end9endmodule
xxxxxxxxxx151// 例 6.182module disp;3 reg[31:0] rval;4 pulldown(pd);5 initial begin6 rval 101;7 ("rval = %h (hex), %d (decimal)", rval, rval);8 ("rval = %o (otal), %b (binary)", rval, rval);9 ("rval has %c ascii character value", rval);10 ("pd strength is %v", pd) // 输出 StX11 ("current scope is %m"); // 输出 disp12 ("%s is ascii value for 101", 101); // e13 ("simulatoin time is %t", time); // 014 end15endmodule
xxxxxxxxxx91// 例 6.192module printval;3 reg[11:0] r1;4 initial begin5 r1 10;6 ("maximum size = %d = %h", r1, r1); // 10, 00a7 ("minimum size = %0d = %0h", r1,r1); // 10, a8 end9endmodule
xxxxxxxxxx161// 例 6.20:文件描述符2integer handle1, handle2; // 整型数为 32 位3integer desc1, desc2, desc3;4
5initial begin6 handle1 ("file1.out"); // 32'h0000_00027 handle2 ("file2.out"); // 32'h0000_00048 9 desc1 handle1 1; // 1 为标准输出 stdout10 (desc1, "Display 1"); // 同时写入 file1.out 和 stdout11 12 desc2 handle2 handle1;13 (desc2, "Display 2"); // 写入 file1.out 和 file2.out14 15 (handle1);16end写文件:$fdisplay, $fmonitor, $fwrite, $fstrobe
xxxxxxxxxx91// 例 6.21:显示层次2module M;3 initial ("%m");4endmodule5
6module top;7 M m1(); // 输出 top.m18 M m2(); // 输出 top.m29endmodule
xxxxxxxxxx81// 例 6.22:选通显示2always @(posedge clock) begin3 a b; c d;4end5
6always @(posedge clock)7 ("a = %b, c= %b", a, c);8// posedge clock 发生时,始终在其它语句完成后才执行 $strobe
xxxxxxxxxx131// 例 6.23:VCD 文件系统任务2initial ("myfile.dmp"); // 仿真信息转储到 myfile.dmp3initial ; // 设计中的全部信息都转储4initial (1, top); // 转出模块示例 top 模块第一层的信号5initial (2, top.m1); // 转储 top.m1 下两层的信号6initial (0, top.m1); // 0 表示各个层的所有信号7
8initial begin9 ; // 启动转储过程10 #100000 ; // 停止转储过程11end12
13initial ; // 转储所有 VCD 变量的现行值
xxxxxxxxxx21(, , "rxd = %b, txd = %b", rxd, txd);2// ', ,' 空参数显示为空格
xxxxxxxxxx101`timescale 10ns1ns2module test;3 reg set;4 initial begin5 (, ", ", , ", ", "set = ", set);6 // 输出: 0, 0, set = x7 #1.6 set 0; // 2, 1.6, set = 08 #1.6 set 1; // 3, 3.2, set = 19 end10endmodule
xxxxxxxxxx71; // 结束仿真2(0); // 结束且不输出任何信息3(1); // 输出当当前仿真时刻和位置4(2); // 输出当前仿真时刻、位置、所有 memory 和 CPU 时间统计5
6; // 暂停仿真 (可在仿真器中点击继续仿真)7(n);
xxxxxxxxxx121// 例 7.3:初始化存储器2module test;3 reg[7:0] memory[0:7]; // 8 个 8 位的存储单元4 integer i;5 6 initial begin7 ("init.dat", memory);8 for (i 0; i < 8; i i 1) begin9 ("Memory[%d] = %b", i, memory[i]);10 end11 end12endmodulexxxxxxxxxx71// init.dat 文件2@002311111111 01010101400000000 101010105
6@00671111zzzz 00001111
xxxxxxxxxx31reg[23:0] rand;2rand ; // 生成 32 位的带符号随机数, 赋给 rand 时取低 24 位3rand 60; // -b+1 ~ b-1
xxxxxxxxxx91`define NUM 8 // 定义宏(无需分号)2a `NUM; // 引用宏3
4`define NUM 8; // 连着分号一起被替换5a `NUM // 于是无需再写分号6
7`define expr abcd // 建议不加分号,以防后续语法出错8
9`define typ_nand nand #5 // 可以包含空格等
状态的编码:使用 Gray 码或独热码
输出的变量:使用新的变量,或者直接把部分状态作为输出
xxxxxxxxxx341// 例 12.1:有限状态机,Gray编码2module fsm(clk, rst, A, K2, K1, state);3 input clk, rst, A;4 output reg K2, K1;5 output reg[1:0] state;6 // Gray 码:7 parameter Idle 2'b00,8 Start 2'b01,9 Stop 2'b10,10 Clear 2'b11;11 // 或者用独热码:12 /*13 parameter Idle = 4'b1000,14 Start = 4'b0100,15 Stop = 4'b0010,16 Clear = 4'b0001;17 */18 19 always @(posedge clk) begin20 if (rst) begin21 state < Idle; K2 < 0; K1 < 1;22 end23 else case (state)24 Idle: if (A) begin25 state < Start; K1 < 0;26 end27 else begin28 state < Idle; K2 < 0; K1 < 0;29 end30 ... // 其它的状态31 default: state < 2'bxx;32 endcase33 end34endmodule
xxxxxxxxxx401// 例 12.42module fsm(Clock, Reset, A, K2, K1);3 input Clock, Reset, A;4 output reg K2, K1;5 reg[1:0] state, nextState;6 7 parameter Idel 2'b00;8 parameter Start 2'b01;9 parameter Stop 2'b10;10 parameter Clear 2'b11;11 12 // 时钟沿产生可能的状态变化13 always @(posedge Clock)14 if (Reset) state < Idle;15 else state < nextState;16 17 // 产生下一状态的组合逻辑18 always @(state or A)19 case (state)20 Idle: nextState < A Start : Idle;21 Start: nextState < A Start : Stop;22 Stop: nextState < A Clear : Stop;23 Clear: nextState < A Clear : Idle;24 default: nextState < 2'bxx;25 endcase26 27 // 输出 K128 always @(state or Reset or A) begin29 if (Reset) K1 < 0;30 else if (state Clear A) K1 < 1;31 else K1 < 0;32 end33 34 // 输出 K235 always @(state or Reset or A) begin36 if (Reset) K2 < 0;37 else if (state Stop A) K2 < 1;38 else K2 < 0;39 end40endmodule
13.5.1 组合逻辑电路
xxxxxxxxxx111// 例 13.1:n 位加法器2module adder(a, b, cin, sum, cout);3 parameter n 8;4 5 input cin;6 input[n1:0] a, b;7 output cout;8 output[n1:0] sum;9 10 assign {cout, sum} a b cin;11endmodule
xxxxxxxxxx241// 例 13.2: 指令译码电路2// 操作码的宏定义3`define plus 3'd04`define minus 3'd15`define band 3'd26`define bor 3'd37`define unegate 3'd48
9module alu(a, b, opcode, out);10 input[2:0] opcode;11 input[7:0] a, b;12 output reg[7:0] out;13 14 always @(opcode or a or b) begin15 case (opcode) 16 `plus: out a b;17 `minus: out a b;18 `band: out a b;19 `bor: out a b;20 `unegate: out a;21 default: out 8'hx;22 endcase23 end24endmodule
xxxxxxxxxx211// 例 13.3: 排序2module sort4(a, b, c, d, ra, rb, rc, rd);3 parameter n 4;4 input[n1:0] a, b, c, d;5 output reg[n1:0] ra, rb, rc, rd;6 7 always @(a or b or c or d) begin: local8 // 如果定义局部变量,则必须有模块名9 reg[n1:0] va, vb, vc, vd;10 {va, vb, vc, vd} {a, b, c, d};11 sort2(va, vc); sort2(vb, vd);12 sort2(va, vb); sort2(vc, vd);13 sort2(vb, vc);14 {ra, rb, rc, rd} {va, vb, vc, vd};15 end16 17 task sort2;18 input[n1:0] x, y;19 if (x > y) {x, y} {y, x};20 endtask21endmodule
xxxxxxxxxx71// 例 13.4:比较器2module compare(equal, a, b);3 parameter size 1;4 input[size1:0] a, b;5 output equal;6 assign equal (ab) 1 : 0;7endmodule
xxxxxxxxxx61// 例 13.5:3-8 译码器2module decoder(in, out);3 input[2:0] in;4 output[7:0] out;5 assign out 1'b1 << in;6endmodule
xxxxxxxxxx501// 例 13.6: 8-3 编码器 12module encoder1(none_on, out, in);3 input[7:0] in;4 output reg[2:0] out;5 output reg none_on;6 7 always @(in) begin: local8 integer i;9 out 0;10 none_on 1;11 for (i 0; i < 8; i i 1) begin12 if (in[i]) begin13 out i;14 none_on 0;15 end16 end17 end18endmodule19
20// 8-3 编码器 2 (优先编码器, 利用 ?: 语句实现)21module encoder2(none_on, out, in);22 input[7:0] in;23 output reg[2:0] out;24 output reg none_on;25 26 wire[3:0] outvec;27 assign outvec in[7] 4'b0111 :28 in[6] 4'b0110 :29 in[5] 4'b0101 :30 in[4] 4'b0100 :31 in[3] 4'b0011 :32 in[2] 4'b0010 :33 in[1] 4'b0001 :34 in[0] 4'b0000 : 4'b1000;35 assign {none_on, out} outvec;36endmodule37
38// 8-3 编码器 3 (优先编码器, 利用 always 语句实现)39module encoder3(none_on, out, in);40 input[7:0] in;41 output[2:0] out;42 output none_on;43 44 reg[3:0] outvec;45 assign {none_on, out} outvec;46 always @(in) begin47 if (in[7]) outvec 4'b0110;48 else if (in[6]) ......49 end50endmodule
xxxxxxxxxx291// 例 13.7: 多路选择器2module emux1(out, a, b, sel);3 input a, b, sel;4 output out;5 assign out sel a : b;6endmodule7
8module emux2(out, a, b, sel);9 input a, b, sel;10 output reg out;11 12 always @(a or b or sel) begin13 case (sel)14 1'b1: out a;15 1'b0: out b;16 default: out 'bx;17 endcase18 end19endmodule20
21module emux3(out, a, b, sel);22 input a, b, sel;23 output reg out;24 25 always @(a or b or sel) begin26 if (sel) out a;27 else out b;28 end29endmodule
xxxxxxxxxx71// 例 13.8: 奇偶校验位生成器2module parity(even_numbits, odd_numbits, input_bus);3 output even_numbits, odd_numbits;4 input[7:0] input_bus;5 assign odd_numbits input_bus;6 assign even_numbits odd_numbits;7endmodule
xxxxxxxxxx131// 例 13.9: 三态输出驱动器 (三态门模型)2module trist1(out, in, enable);3 input in, enable;4 output out;5 assign out enable in : 'bz;6endmodule7
8module trist2(out, in, enable)9 input in, enable;10 output out;11 // bufif1 是一个 Verilog 门级原语12 bufif1 mybuf1(out, in, enable);13endmodule
xxxxxxxxxx81// 例 13.10: 三态双向驱动器2module bidir(tri_inout, out, in, en, b);3 input tri_inout;4 output out;5 input in, en, b;6 assign tri_inout en in : 'bz;7 assign out tri_inout b;8endmodule
13.5.2 时序逻辑电路
xxxxxxxxxx91// 例 13.11: 触发器2module dff(q, data, clk);3 input data, clk;4 output reg q;5 6 always @(posedge clk) begin7 q < data;8 end9endmodule
xxxxxxxxxx61// 例 13.12: 电平敏感型锁存器2module latch1(q, data, clk);3 input data, clk;4 output q;5 assign q clk data : q;6endmodule
xxxxxxxxxx61// 例 13.13: 带置位和复位端的电平敏感型锁存器2module latch2(q, data, clk, set, reset);3 input data, clk, set, reset;4 output q;5 assign q reset 0 : (set 1 (clk data : q));6endmodule
xxxxxxxxxx71// 例 13.14: 电平敏感型锁存器2module latch(q, data, clk);3 input data, clk;4 output reg q;5 6 always @(clk) q < data;7endmodule
xxxxxxxxxx131// 例 13.15: 移位寄存器2module shifter(din, clk, clr, dout);3 input din, clk, clr;4 output reg[7:0] dout;5 6 always @(posedge clk) begin7 if (clk) dout < 8'b0;8 else begin9 dout < dout << 1;10 dout[0] < din;11 end12 end13endmodule
xxxxxxxxxx321// 例 13.16: 8 位计数器2module counter1(out, data, load, cin, clk);3 input[7:0] data;4 input load, cin, clk;5 output reg[7:0] out;6 output cout;7 8 always @(posedge clk) begin9 if (load) out < data;10 else out < out cin;11 end12 13 assign cout (out) cin;14 // &out 当且仅当 out 所有位都为 1 时才为 115endmodule16
17module counter2(out, cout, data, load, cin, clk);18 input[7:0] data;19 input load, cin, clk;20 output reg[7:0] out;21 output reg cout;22 23 reg[7:0] preout;24 always @(posedge) begin25 out < preout;26 end27 28 always @(out or data or load or cin) begin29 {cout, preout} out cin;30 if (load) preout data;31 end32endmodule